//
//  AudioPlayer.m
//  test
//
//  Created by ltr on 16/4/12.
//  Copyright © 2016年 ltr. All rights reserved.
//

#import "AudioPlayer.h"
#import <AVFoundation/AVFoundation.h>
#import <UIKit/UIKit.h>

#define kAudioQueueBufferSize   4        //音频缓冲队列的最大数
#define kAudioPCMBufferSize   1024*10  //音频解码后pcm数据最大size

typedef enum : NSUInteger {
    AudioPlayerNull     = 0,
    AudioPlayerInited   = 1,
    AudioPlayerPlaying  = 2,
    AudioPlayerPause    = 3,
    AudioPlayerStop     = 4,
} AudioPlayerStatus;

@interface AudioPlayer()
{
    AudioStreamBasicDescription _audioDescription;///音频参数
    AudioQueueRef               _audioQueue;//音频播放队列
    AudioQueueBufferRef         _audioQueueBuffers[kAudioQueueBufferSize];//音频缓存
    
    NSLock          *_lock;
    NSMutableArray  *_audioDataArray;
    
    double          _sampleRate;
    UInt32          _channels;
    UInt32          _sampleBits;
}

@property (nonatomic, assign, readonly) AudioPlayerStatus audioStatus;//0-未初始化或已析构，1-初始化，2-播放，3-暂停，4-停止=0

@end

@implementation AudioPlayer

- (id)init
{
    self = [super init];
    if (self) {
        _audioStatus = AudioPlayerNull;
        _lock = [[NSLock alloc] init];
        _audioDataArray = [[NSMutableArray alloc] init];
        [self audioPlayerNotificationSetUp];
    }
    return self;
}

- (void)dealloc
{
    [self audioPlayerSetDown];
    [self audioPlayerNotificationSetDown];
    NSLog(@"AudioPlayer dealloc");
}

#pragma mark - pcm数据添加
- (void)addPCM:(void *)pcmBytes length:(UInt32)pcmLength timeStamp:(UInt32)timeStamp
{
    [_lock lock];
    PCMData *pcmData = [[PCMData alloc] initWithBytes:pcmBytes length:pcmLength timeStamp:timeStamp];
    [_audioDataArray addObject:pcmData];
    [_lock unlock];
}

- (PCMData *)getPcm
{
    [_lock lock];
    if (_audioDataArray.count > 0) {
        PCMData *pcmData = [_audioDataArray objectAtIndex:0];
        [_audioDataArray removeObjectAtIndex:0];
        [_lock unlock];
        return pcmData;
    }
    [_lock unlock];
    return nil;
}

- (void)clearPCM
{
    [_lock lock];
    [_audioDataArray removeAllObjects];
    [_lock unlock];
}

#pragma mark - 播放器初始化
- (void)setSampleRate:(double)sampleRate channels:(UInt32)channels sampleBits:(UInt32)sampleBits
{
    _sampleRate = sampleRate;
    _channels = channels;
    _sampleBits = sampleBits;
    
    if (_audioStatus != AudioPlayerNull){
        [self audioPlayerSetDown];
    }
    
    [self audioPlayerSetUp];
    [self clearPCM];
    [self audioPlayerInBackground];
    [self audioPlayerStart];
}

- (void)audioPlayerNotificationSetUp
{
    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(interruption:) name:AVAudioSessionInterruptionNotification object:nil];
    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(didBecomActive:) name:UIApplicationDidBecomeActiveNotification object:nil];
    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(willResignActive:) name:UIApplicationWillResignActiveNotification object:nil];
}

- (void)audioPlayerNotificationSetDown
{
    [[NSNotificationCenter defaultCenter] removeObserver:self name:AVAudioSessionInterruptionNotification object:nil];
    [[NSNotificationCenter defaultCenter] removeObserver:self name:UIApplicationDidBecomeActiveNotification object:nil];
    [[NSNotificationCenter defaultCenter] removeObserver:self name:UIApplicationWillResignActiveNotification object:nil];
}

- (void)interruption:(NSNotification *)notification
{
    NSDictionary *dictionary = notification.userInfo;
    NSInteger interruption = [[dictionary objectForKey:AVAudioSessionInterruptionTypeKey] integerValue];
    if (interruption == AVAudioSessionInterruptionTypeBegan) {
        NSLog(@"Audio:AVAudioSessionInterruptionTypeBegan");
        _audioStatus = AudioPlayerPause;
        //[self audioPlayerPuase];
    }
    if (interruption == AVAudioSessionInterruptionOptionShouldResume) {
        NSLog(@"AVAudioSessionInterruptionOptionShouldResume");
        //[self audioPlayerStart];
    }
}

- (void)didBecomActive:(NSNotification *)notification
{
    if (_audioStatus == AudioPlayerPause) {
        [self replayer];
    }
}

- (void)willResignActive:(NSNotification *)notification
{
    
}

#pragma mark - 音频流播放
- (void)audioPlayerInBackground
{
    //允许后台播放
    NSError *error = nil;
    AVAudioSession *session = [AVAudioSession sharedInstance];
    [session setActive:YES error:nil];
    [session setCategory:AVAudioSessionCategoryPlayback error:nil];
    if (error) {
        NSLog(@"ERROR: setCategory %@", [error localizedDescription]);
    }
}

- (void)replayer
{
    [self audioPlayerSetDown];
    [self audioPlayerSetUp];
    [self clearPCM];
    [self audioPlayerStart];
}

- (void)audioPlayerStart
{
    AudioQueueStart(_audioQueue, 0);
    _audioStatus = AudioPlayerPlaying;
}

- (void)audioPlayerPuase
{
    AudioQueuePause(_audioQueue);
    _audioStatus = AudioPlayerPause;
}

-(void)audioPlayerStop
{
    AudioQueueStop(_audioQueue, TRUE);
    _audioStatus = AudioPlayerStop;
}

- (void)setVolume:(float)volume {
    AudioQueueSetParameter(_audioQueue, kAudioQueueParam_Volume, volume);
}

- (void)audioPlayerSetDown
{
    if(_audioQueue){
        AudioQueueFlush(_audioQueue);
        AudioQueueReset(_audioQueue);
        AudioQueueStop(_audioQueue, TRUE);
        
        for(int  i = 0;i < kAudioQueueBufferSize; i ++){
            AudioQueueFreeBuffer(_audioQueue, _audioQueueBuffers[i]);
            _audioQueueBuffers[i] = nil;
        }
        _audioQueue = nil;
    }
    _audioStatus = AudioPlayerNull;
}

- (void)audioPlayerSetUp
{
    ///设置音频参数
    _audioDescription.mSampleRate = _sampleRate;//采样率
    _audioDescription.mFormatID = kAudioFormatLinearPCM;
    _audioDescription.mFormatFlags = kLinearPCMFormatFlagIsSignedInteger | kAudioFormatFlagIsPacked;
    _audioDescription.mChannelsPerFrame = _channels;//2;//2声道
    _audioDescription.mFramesPerPacket = 1;//每一个packet一侦数据
    _audioDescription.mBitsPerChannel = _sampleBits;//16;//每个采样点16bit量化
    _audioDescription.mBytesPerFrame = (_audioDescription.mBitsPerChannel/8) * _audioDescription.mChannelsPerFrame;
    _audioDescription.mBytesPerPacket = _audioDescription.mBytesPerFrame ;
    
    ///创建一个新的从audioqueue到硬件层的通道
    //AudioQueueNewOutput(&_audioDescription, AudioPlayerAQInputCallback, (__bridge void*)self, CFRunLoopGetCurrent(), kCFRunLoopCommonModes, 0, &_audioQueue);///使用当前线程播
    AudioQueueNewOutput(&_audioDescription, audioQueueOutputCallback, (__bridge void *)(self), nil, nil, 0, &_audioQueue);//使用player的内部线程播
    ////添加buffer区
    OSStatus result = 0;
    for(int i = 0;i < kAudioQueueBufferSize; i++){
        result =  AudioQueueAllocateBuffer(_audioQueue, kAudioPCMBufferSize, &_audioQueueBuffers[i]);///创建buffer区，MIN_SIZE_PER_FRAME为每一侦所需要的最小的大小，该大小应该比每次往buffer里写的最大的一次还大
        if (result >= 0) {
            _audioQueueBuffers[i]->mAudioDataByteSize = kAudioPCMBufferSize;
            memset(_audioQueueBuffers[i]->mAudioData, 0, kAudioPCMBufferSize);
            AudioQueueEnqueueBuffer(_audioQueue, _audioQueueBuffers[i], 0, NULL);
        } else {
            NSLog(@"AudioPlayer Error!");
        }
    }
    
    _audioStatus = AudioPlayerInited;
}

static void audioQueueOutputCallback(void *input, AudioQueueRef outQ, AudioQueueBufferRef outQB)
{
    AudioPlayer *audioPlayer = (__bridge AudioPlayer *)input;
    
    PCMData *pcm = [audioPlayer getPcm];
    if(pcm){
        outQB->mAudioDataByteSize = pcm.length;
        memcpy(outQB->mAudioData, pcm.pcmBytes, pcm.length);
        AudioQueueEnqueueBuffer(outQ, outQB, 0, NULL);
        
        if (audioPlayer.delegate && [audioPlayer.delegate respondsToSelector:@selector(audioPlayedTimeStamp:)]) {
            [audioPlayer.delegate audioPlayedTimeStamp:pcm.timeStamp];
        }
    }else{
        memset(outQB->mAudioData, 0, outQB->mAudioDataByteSize);
        AudioQueueEnqueueBuffer(outQ, outQB, 0, NULL);
    }
}

@end

@implementation PCMData

- (instancetype)initWithBytes:(void *)bytes length:(UInt32)length timeStamp:(UInt32)timeStamp
{
    self = [super init];
    if (self) {
        _pcmBytes = calloc(length, sizeof(char));
        memcpy(_pcmBytes, bytes, length);
        _length = length;
        _timeStamp = timeStamp;
    }
    return self;
}

- (void)dealloc {
    if (_pcmBytes) {
        free(_pcmBytes);
        _pcmBytes = NULL;
    }
    _length = 0;
}

@end
